<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Live</title>
    <link rel="stylesheet" href="http://127.0.0.1:3003/index.css">
    <link rel="stylesheet" href="http://127.0.0.1:3003/liveInformation.css">
    <link rel="stylesheet" href="http://127.0.0.1:3003/element.css">
    <!--<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script src="http://127.0.0.1:3003/adapt.js"></script>
    <!--<script src="http://127.0.0.1:3003/adapter_hacks.js"></script>-->
    <!--<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>-->
    <script src="http://127.0.0.1:3003/obtainStats.js"></script>
    <script src="http://127.0.0.1:3003/element.js"></script>
    <!--<script src="https://unpkg.com/element-ui/lib/index.js"></script>-->
</head>
<body>
<div id="app">
    <div class="login" v-show="flag">
        <h3>观看直播前，请输入您的昵称</h3>
        <div class="nameWrapper">
            <el-autocomplete
                    popper-class="autoComplete "
                    class="input"
                    v-model="userName"
                    v-show="flag"
                    :fetch-suggestions="querySearch"
                    placeholder="请输入昵称"
                    @keyup.enter.native="sendName"
                    @select="handleSelect"
                    clearable
                    autofocus
            ></el-autocomplete>
            <el-button type="primary" @click="sendName">提交昵称</el-button>
        </div>
    </div>
    <div class="live" v-show="!flag">
        <div class="liveInner">
            <div class="wrapper">
                <video id="video" autoplay width="640px" height="360px" controls poster="http://127.0.0.1:3003/bg.jpg">
                    你的浏览器不支持 <code>video</code> 标签
                </video>
            </div>
            <div class="chat">
                <div class="content">
                    <div class="message">
                        <div class="container" ref="scroll">
                            <div class="userMessages" v-for="item in messages">
                                {{item.watcherName}}：{{item.watcherMessage}}
                            </div>
                        </div>
                        <div class="sendMessage">
                            <el-input
                                    type="textarea"
                                    :rows="2"
                                    placeholder="请输入内容"
                                    v-model="message">
                            </el-input>
                            <el-button type="primary" @click="sendMessage" plain>发送</el-button>
                        </div>
                    </div>
                    <div class="watcherList">
                        <p>在线{{userNames.length}}人</p>
                        <div v-for="name in userNames" class="nameList">
                            <p>{{name}}</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <img src="http://127.0.0.1:3003/arrow.png" width="50" height="50" @click="liveInformationShow">
    </div>
    <div class="liveInformation" v-show="informationShow">
        <div class="left">
            <img src="http://127.0.0.1:3003/arrow.png" width="50" height="50" @click="liveInformationClose">
        </div>
        <div class="right">
            <div class="behaviourShow">
                <div class="behaviourDetailTop">
                    <p>Connection Event:</p>
                    <ul @click="searchContent">
                        <li v-for="(item,index) in behaviour" :data-address="index">
                            {{item[item.length-1]==="主播" ? (item[1]===null ? "主播" :
                            userNamesAll[item[1].split('_')[1]]):item[item.length-1] }} {{item[0]}}
                        </li>
                    </ul>
                </div>
                <div class="behaviourDetail">
                    <p>Detail</p>
                    <div class="behaviourContent">
                        <div v-if="typeof behaviourContent === 'object'">
                            <p v-for="(value,key) in behaviourContent">{{key}}:{{value}}</p>
                        </div>
                        <div v-else>{{behaviourContent}}</div>
                    </div>
                </div>
            </div>
            <div class="statsShow">
                <p>Connection Stats: </p>
                <div class="statsDetailTop">
                    <div v-for="ele in currentStats" class="statsEle">
                        <p>{{userNamesAll[ele.count]}}</p>
                        <ul @click="chooseStatsShow">
                            <li v-for="(value,key) in ele" v-show="indicator.includes(key)" :data-stats="key">{{key}}: {{value}}</li>
                        </ul>
                    </div>
                </div>
                <div class="statsDetail">
                    <p>Detail</p>
                    <div v-if="userName!=='主播'" class="canvasWrapper">
                        <canvas width="100" height="100" id="canvas"></canvas>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
<script>
    var socket = io.connect()
    var anchor = new Map(), watcher, userID, localStream, canvasCase
    var app = new Vue({
        el: '#app',
        data: {
            show: true,
            flag: true,
            userName: '',
            userNames: [],  //当前连接的用户名
            userNamesAll: [], //所有连接过的用户名
            message: '',
            messages: [],
            behaviour: window._behaviour,
            behaviourContent: '',
            count: 0,
            currentStats: [],
            storgeStats:{
                axis:[0],
                packetsSent: [0],
                packetsReceived:[0],
                packetsLost:[0],
                bitrateMean:[0],
                bitrateStdDev:[0],
                discardedPackets:[0],
                firCount:[0],
                jitter:[0]
            },
            informationShow: false,
            restaurants: [],
            indicator: ['mediaType', 'packetsSent', 'packetsLost', 'packetsReceived','bitrateMean','bitrateStdDev','discardedPackets','firCount','jitter'] // 决定哪些性能指标会显示
        },
        watch: {
            messages() {
                this.$nextTick(() => {
                    this.$refs.scroll.scrollTop = this.$refs.scroll.scrollHeight
                })
            },
            currentStats() {
                if(this.userName!=='主播'){
                    if (this.count !== this.currentStats.length) {
                        this.createCanvas(this.count)
                        this.count = this.currentStats.length
                    }else{
                        if(this.storgeStats.axis.length>=10){
                            let keys=Object.keys(this.storgeStats)
                            keys.forEach(ele=>{
                                this.storgeStats[ele].shift()
                            })
                        }
                        this.currentStats.forEach(item=>{
                            let keys=Object.keys(this.storgeStats)
                            keys.forEach(ele=>{
                                if(ele==='axis'){
                                    this.storgeStats[ele].push(this.storgeStats.axis[this.storgeStats.axis.length-1]+3)
                                }else{
                                    this.storgeStats[ele].push(item[ele])
                                }
                            })
                            canvasCase.data.labels=this.storgeStats.axis
                            canvasCase.data.datasets[0].data=this.storgeStats[canvasCase.data.datasets[0].label]
                            canvasCase.update()
                        })
                    }
                }
            }
        },
        methods: {
            openErrorMessage() {
                this.$message.error('昵称中不能含有任何空白字符，包括空格、制表符！')
            },
            openWarnMessage() {
                this.$message({
                    message: '对不起，您输入的用户名已存在，请重新输入！',
                    type: 'warning'
                });
            },
            querySearch(queryString, cb) {
                var restaurants = this.restaurants;
                var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
                // 调用 callback 返回建议列表的数据
                cb(results);
            },
            createFilter(queryString) {
                return (restaurant) => {
                    return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
                };
            },
            loadAll() {
                return [
                    {"value": "美国队长"},
                    {"value": "鸣人"},
                    {"value": "梅西"},
                    {"value": "000"}
                ]
            },
            handleSelect(item) {
//                console.log(item);
            },
            sendMessage() {
                if (this.message !== '') {
                    let data = {'watcherName': this.userName, 'watcherMessage': this.message}
                    this.messages.push(data)
                    socket.emit('sendMessage', data)
                    this.message = ''
                }
            },
            sendName() {
                var that = this
                if (that.userName !== '' && that.userName.search(' ') == -1) {
                    socket.emit('userName', that.userName, function (data) {
                        if (data) {
                            that.$message.closeAll()
                            document.querySelector('.autoComplete').style.display = 'none'
                            that.flag = false
                        } else {
                            that.openWarnMessage()
                        }
                    })
                } else {
                    that.openErrorMessage()
                }
            },
            searchContent(event) {
                this.behaviourContent = this.behaviour[event.target.getAttribute('data-address')][2]
            },
            liveInformationShow() {
                this.informationShow = true
            },
            liveInformationClose() {
                this.informationShow = false
            },
            createCanvas(n) {
                if(this.userName!=="主播"){
                    var ctx = document.querySelector('#canvas').getContext('2d')
                    canvasCase = new Chart(ctx, {
                        type: 'line',
                        data: {
                            labels: [0],
                            datasets: [{
                                label: "packetsReceived",
                                backgroundColor: 'rgb(255, 99, 132)',
                                borderColor: 'rgb(255, 99, 132)',
                                data: [0]
                            }]
                        },
                        options: {
                            responsive: true,
                            legend: {
                                display: false
                            },
                            layout: {
                                padding: {
                                    left: 0,
                                    right: 0,
                                    top: 0,
                                    bottom: 30
                                }
                            }
                        }
                    })
                }
            },
            chooseStatsShow(event) {
                if(event.target.getAttribute('data-stats')!=='mediaType'){
                    canvasCase.data.labels=this.storgeStats.axis
                    canvasCase.data.datasets[0].label=event.target.getAttribute('data-stats')
                    canvasCase.data.datasets[0].data=this.storgeStats[event.target.getAttribute('data-stats')]
                    canvasCase.update()
                }
            }
        },
        mounted() {
            this.restaurants = this.loadAll();
        }
    })

    socket.on('live', function () {
        console.log('主播上线了')
        app.userName = '主播'
        var constraints = {
            audio: false,
            video: {
                mandatory: {
                    minWidth: 640,
                    minHeight: 360,
                    maxWidth: 1280,
                    maxHeight: 720
                }
            }
        }
        navigator.mediaDevices.getUserMedia(constraints).then(handleSuccess).catch(handleError)
    })

    socket.on('addWatcher', function (data) {
        console.log('有新的观看者')
        let watcherID = data
        anchor.set(watcherID, new RTCPeerConnection())
        anchor.get(watcherID).addStream(localStream)
        anchor.get(watcherID).createOffer().then((offer) => {
            anchor.get(watcherID).setLocalDescription(offer).then(sendLiveOffer(watcherID, offer))
        })
        anchor.get(watcherID).onicecandidate = function (event) {
            if (event.candidate) {
                socket.emit('anchorIce', {'ice': event.candidate, 'target': watcherID})
            }
        }
    })

    function handleSuccess(stream) {
        document.getElementById("video").srcObject = stream
        localStream = stream
    }

    function handleError(error) {
        console.log('There is an error: ' + error)
    }

    function sendLiveOffer(targetId, offer) {
//        let sdp = anchor.get(targetId).localDescription
        let sendOffer = {
            name: 'anchor',
            target: targetId,
            type: "video-offer",
            sdp: offer
        }
        socket.emit('sendOffer', sendOffer)
        console.log('offer 已发出')
    }

    socket.on('watcherAnswer', function (data) {
        console.log('answer 已收到')
//        var desc = new RTCSessionDescription(data.sdp)
        app.userNamesAll.push(data.userName)
        anchor.get(data.name).setRemoteDescription(data.sdp).then(() => {
            console.log('PeerConnection success')
        })
    })

    socket.on('receiveWatcherIce', function (data) {
        anchor.get(data.name).addIceCandidate(new RTCIceCandidate(data.ice))
    })

    socket.on('watcherLeave', function (data) {
        anchor.get(data).onicecandidate = null
        anchor.get(data).onaddstream = null
        anchor.get(data).close()
        anchor.set(data, null)
        anchor.delete(data)
    })

    //    watcher code
    socket.on('watch', function (data) {
        console.log('观看直播中')
        console.log('offer 已收到')
        watcher = new RTCPeerConnection()
//        let desc = new RTCSessionDescription(data.sdp)
//        watcher.setRemoteDescription(desc).then(createAnswer)
        watcher.setRemoteDescription(data.sdp).then(createAnswer)
        watcher.onaddstream = function (e) {
            document.getElementById("video").srcObject = e.stream
            console.log('add stream success')
        }
        watcher.onicecandidate = function (event) {
            if (event.candidate) {
                socket.emit('watcherIce', {'ice': event.candidate, name: userID})
            }
        }
    })

    socket.on('receiveAnchorIce', function (data) {
        if (data) {
            watcher.addIceCandidate(new RTCIceCandidate(data))
        }
    })

    socket.on('welcome', function (data) {
        userID = data.socketID
        if (data.liveAddress === null) {
            app.online = true
        }
    })

    socket.on('receiveMessage', function (data) {
        app.messages.push(data)
    })

    socket.on('userNames', function (data) {
        app.userNames = data
    })

    function createAnswer() {
        watcher.createAnswer().then((answer) => {
//            var str='a=ssrc:3058302899 cname:HihGWrlNlFKu4p2q\n'
//            answer.sdp += str
//            console.log(answer.sdp)
//            console.log('----------')
//            console.log(watcher.remoteDescription.sdp)
            watcher.setLocalDescription(answer).then(sendAnswer(answer))
        }).catch(rej => console.log(rej))
    }

    function sendAnswer(answer) {
        socket.emit('sendAnswer', {
            name: userID,
            userName: app.userName,
            type: 'video-answer',
            sdp: answer
        })
        console.log('answer 已发出')
    }
</script>
</html>